"""
Library providing functions to the controller to translate
between local time (in the views) and UTC time (in the model)
"""

import datetime

NO_CLOCKOUT_DATETIME = datetime.datetime(1900, 1, 1)
#TODO: dedupe this variable

def get_date_range(from_date_str, to_date_str):
    local_from_datetime = string_to_datetime(from_date_str, "%m/%d/%Y")
    local_to_datetime = string_to_datetime(to_date_str, "%m/%d/%Y")
    next_day = local_from_datetime
    return_list = []
    while next_day <= local_to_datetime:
        return_list.append(next_day)
        next_day += datetime.timedelta(days=1)
    return return_list


def get_today_daystart_and_tomorrow_in_utc():
    local_now_dt = get_local_now_dt()
    daystart_utc, dayafter_daystart_utc = get_daystart_and_tomorrow_in_utc(local_now_dt)
    return daystart_utc, dayafter_daystart_utc


def get_daystart_and_tomorrow_in_utc(local_now_dt):
    daystart, dayafter_daystart = get_datestart_and_next_day(local_now_dt)
    daystart_utc = convert_to_UTC(daystart)
    dayafter_daystart_utc = convert_to_UTC(dayafter_daystart)
    return daystart_utc, dayafter_daystart_utc


def get_datestart_and_next_day(input_datetime):
    input_datetime_daystart = get_date_start_from_datetime(input_datetime)
    dayafter_datetime_daystart = input_datetime_daystart + datetime.timedelta(days=1)
    return input_datetime_daystart, dayafter_datetime_daystart


def get_date_start_from_datetime(input_datetime):
    date_obj = input_datetime.date()
    return datetime.datetime(date_obj.year, date_obj.month,
        date_obj.day)


def convert_to_UTC(naive_datetime_obj):
    """
    Returns a datetime object in UTC
    """
    mt_datetime_obj = naive_datetime_obj.replace(tzinfo=Mountain_tzinfo())
    utc_datetime_obj = mt_datetime_obj.astimezone(UTC_tzinfo())
    return utc_datetime_obj


def convert_to_localtime(naive_utc_datetime_obj):
    """
    Returns a datetime object in localtime
    given a naive datetime object in UTC
    TODO: make this work for any timezone (could use pytz and timezone config page)
    """
    if naive_utc_datetime_obj == NO_CLOCKOUT_DATETIME:
        return naive_utc_datetime_obj
        # add UTC tzinfo obj to naive datetime obj
    utc_datetime_obj = naive_utc_datetime_obj.replace(tzinfo=UTC_tzinfo())
    # convert the UTC tzinfo obj to local tzinfo obj
    local_datetime_obj = utc_datetime_obj.astimezone(Mountain_tzinfo())
    # TODO: make work with configured local timezone instead of hardcoded
    return local_datetime_obj


def get_local_now_dt():
    """convenience function to get local now datetime"""
    utc_now_dt = datetime.datetime.now()
    local_now_dt = convert_to_localtime(utc_now_dt)
    return local_now_dt


def string_to_datetime(datetime_string, format="%Y-%m-%d %H:%M:%S"):
    """
    converts a string of yyyy-mm-dd HH:MM:SS to a datetime object
    """
    datetime_obj = datetime.datetime.strptime(datetime_string, format)
    return datetime_obj

    # tzinfo implementation


class Mountain_tzinfo(datetime.tzinfo):
    """Implementation of the Mountain timezone."""

    def utcoffset(self, dt):
        return datetime.timedelta(hours=-7) + self.dst(dt)

    def _FirstSunday(self, dt):
        """First Sunday on or after dt."""
        return dt + datetime.timedelta(days=(6 - dt.weekday()))

    def dst(self, dt):
        # 2 am on the second Sunday in March
        dst_start = self._FirstSunday(datetime.datetime(dt.year, 3, 8, 2))
        # 1 am on the first Sunday in November
        dst_end = self._FirstSunday(datetime.datetime(dt.year, 11, 1, 1))

        if dst_start <= dt.replace(tzinfo=None) < dst_end:
            return datetime.timedelta(hours=1)
        else:
            return datetime.timedelta(hours=0)

    def tzname(self, dt):
        if self.dst(dt) == datetime.timedelta(hours=0):
            return "MST"
        else:
            return "MDT"


class UTC_tzinfo(datetime.tzinfo):
    def utcoffset(self, dt): return datetime.timedelta(0)

    def dst(self, dt): return datetime.timedelta(0)

    def tzname(self, dt): return 'UTC'

    def olsen_name(self): return 'UTC'

